package ArithmeticLibrary.Util;

import java.math.BigInteger;

/**
 * This class represents a point on a plane such that x and y are BigInteger.
 * Invariant: either both coordinates not -1 thus representing 'infinity point' or both are not -1
 * 
 * @author Lea Golan
 *
 */
public class Point {
	
	private BigInteger x;//x coordinate of the point
	private BigInteger y;//y coordinate of the point
	private boolean isInfinity;//true iff both x and y are -1
	
	/**
	 * constructs a new point according to the parameters only if invariant holds for x, y
	 * 
	 * @param x - x coordinate
	 * @param y - y coordinate
	 * @throws Exception if for the given parameters the invariant isn't true
	 */
	public Point(BigInteger x, BigInteger y) throws Exception {
		this.x = x;
		this.y = y;
		if (isInfinityCoordinate(x) && isInfinityCoordinate(y)){
			this.setInfinity(true);
		}
		else if (isInfinityCoordinate(x) || isInfinityCoordinate(y)){ 
			throw new Exception("Error: exactly one of the field elements has coordinate of infifnity point");
		}
	}

	private boolean isInfinityCoordinate(BigInteger num){
		return (num.compareTo(BigInteger.valueOf(-1)) == 0);
	}
	
	private void setInfinity(boolean b) {
		this.isInfinity = b;	
	}

	/**
	 * sets the x coordinate only if invariant still holds.
	 * 
	 * @param x - new x coordinate
	 * @throws Exception - if for the given parameter the invariant isn't true 
	 */
	public void setX(BigInteger x) throws Exception {
		if (isInfinityCoordinate(x) && !isInfinityCoordinate(y)){
			throw new Exception("Error: exactly one of the field elements is null");
		}
		this.x = x;
	}

	/**
	 * getter for x
	 * @return the x coordinate of this
	 */
	public BigInteger getX() {
		return x;
	}

	/**
	 * sets the y coordinate only if invariant still holds.
	 * 
	 * @param y - new y coordinate
	 * @throws Exception - if for the given parameter the invariant isn't true 
	 */
	public void setY(BigInteger y) throws Exception {
		if (!isInfinityCoordinate(x) && isInfinityCoordinate(y)){
			throw new Exception("Error: one of the field elements is null");
		}
		this.y = y;
	}

	/**
	 * getter for y
	 * @return the y coordinate of this
	 */
	public BigInteger getY() {
		return y;
	}
	
	/**
	 * @return true iff x==-1 and y==-1
	 */
	public boolean isInfinity(){
		return this.isInfinity;
	}
	
	/**
	 * checks if other is point that holds the same x,y values
	 */
	public boolean equals(Object other){
		if (other == this){
			return true;
		}
		if (!(other instanceof Point)){
			return false;
		}
		return ((this.x.equals(((Point) other).x)) && (this.y.equals(((Point) other).y)));
	}
	
	/**
	 * returns a string representation of the point
	 */
	public String toString(){
		return "("+this.x+", "+this.y+")";
	}
	
}
